/*
 * Project Porcupine
 * Copyright (C) 2012  Team Porcupine
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.towerdive.porcupine;

import com.towerdive.porcupine.maps.GroundMap;
import com.towerdive.porcupine.maps.DungeonMap;
import com.jme3.app.Application;
import com.jme3.bullet.BulletAppState;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Node;
import com.jme3.scene.control.CameraControl.ControlDirection;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Martin "quill18" Glaude <quill18@towerdive.com>
 */


public class GroundAppState extends AbstractAppState {
    private SimpleApplication app;
    private Node rootNode = new Node("Ground Root Node");
    private Node mapNode = new Node("Map Node");

    public Node getRootNode(){
        return rootNode;
    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        super.initialize(stateManager, app); 
        this.app=(SimpleApplication)app;
        
        setupLights();
        
        /**
         * Generate a simple dungeon-style tile map
         */
        GroundMap map = new DungeonMap(mapNode);
        
        /**
         * Populate our world space with it
         */
        try {
            map.PopulateScene(Main.app.getStateManager().getState(BulletAppState.class), Main.app.getAssetManager());
            mapNode = map.getMapNode();
            rootNode.attachChild(mapNode);
            
            SetupCamera(map.getPlayerNode());
            registerInput(map.getPlayerNode());
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to populate scene.", ex);
        }
        
        /**
         * We are overriding the scene's default root node with a new node.
         * Note that we could just attach our node to the default root node
         * instead, which has other implications -- see our update() function.
         */
        app.getViewPort().attachScene(getRootNode());
    }    

    @Override
    public void update(float tpf) {
        super.update(tpf);
        
        /**
         * Because we created a new root node instead of attaching to
         * SimpleApplication's rootNode, we have to manually call these
         * functions.  Note that JME warns us that these calls are unneccessary
         * in JME3, but this doesn't appear to be accurate!
         */
        rootNode.updateLogicalState(tpf);
        rootNode.updateGeometricState();
    }

    /**
     * Add a main light and a fill light to our scene. Note that models with
     * the Lighted material need lights to be visible.
     */
    private void setupLights() {
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(1,-1,-2).normalizeLocal());
        sun.setColor(ColorRGBA.White);
        rootNode.addLight(sun);

        DirectionalLight fill_light = new DirectionalLight();
        fill_light.setDirection(new Vector3f(-1,1,2).normalizeLocal());
        fill_light.setColor(ColorRGBA.Gray);
        rootNode.addLight(fill_light);    
    }

    /**
     * Create the camera Node and attach to the player
     */
    private void SetupCamera(Node playerNode) {
        CameraNode camNode = new CameraNode("Camera Node", Main.app.getCamera());
        camNode.setControlDir(ControlDirection.SpatialToCamera);
        playerNode.attachChild(camNode);
        camNode.setLocalTranslation(new Vector3f(0,20,0.01f));
        camNode.lookAt(playerNode.getLocalTranslation(), Vector3f.UNIT_Y);
    }

    /**
     * Setup key bindings.
     * @param playerNode 
     */
    public void registerInput(Node playerNode) {
        InputManager inputManager = Main.app.getInputManager();

        inputManager.addMapping("moveForward", new KeyTrigger(KeyInput.KEY_UP), new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("moveBackward", new KeyTrigger(KeyInput.KEY_DOWN), new KeyTrigger(KeyInput.KEY_S));
        inputManager.addMapping("moveRight", new KeyTrigger(KeyInput.KEY_RIGHT), new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("moveLeft", new KeyTrigger(KeyInput.KEY_LEFT), new KeyTrigger(KeyInput.KEY_A));
        
        inputManager.addMapping("zoomIn", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false), 
                                          new KeyTrigger(KeyInput.KEY_PGUP));
        inputManager.addMapping("zoomOut", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true),
                                           new KeyTrigger(KeyInput.KEY_PGDN));
        
        KeyboardHandler playerInput = new KeyboardHandler(playerNode);
        inputManager.addListener(playerInput, "moveForward", "moveBackward", "moveRight", "moveLeft");
        inputManager.addListener(playerInput, "zoomIn", "zoomOut");
        
        // Create the Mouse object.
        //mouse = new AbsoluteMouse("MyMouse", display.getWidth(), display.getHeight());
        //mouse.registerWithInputHandler(input);
       
        // Give the mouse a new cursor.
        //URL url = this.getClass().getClassLoader().getResource("Textures/cursor.png");
        //MouseInput.get().setCursorVisible(true);
        //MouseInput.get().setHardwareCursor(url);
        
        inputManager.addMapping("clickPrimary", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        inputManager.addMapping("mouseMovement", new MouseAxisTrigger(MouseInput.AXIS_X, true));
        inputManager.addMapping("mouseMovement", new MouseAxisTrigger(MouseInput.AXIS_Y, true));
        inputManager.addMapping("mouseMovement", new MouseAxisTrigger(MouseInput.AXIS_X, false));
        inputManager.addMapping("mouseMovement", new MouseAxisTrigger(MouseInput.AXIS_Y, false));
        MouseHandler mouseHandler = new MouseHandler(inputManager, Main.app.getCamera(), rootNode);
        mapNode.addControl(mouseHandler);
        inputManager.addListener(mouseHandler, "clickPrimary");
    }
}
